
package com.sun.shine.myrotation.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;


import static java.lang.Math.PI;
public class RotatView_add_new_point extends View {
    float o_x;
    float o_y;
    Handler handler;
    int delayedTime = 20;
    static final int play = 0;
    static final int stop = 1;
    double currentTime = 0;
    int width;
    int height;
    double maxwidth;
    Bitmap rotatBitmap;

    Double dir_x = 0d;
    Double dir_y = 0d;
    Double dir_z = 0d;
    Double dir_w = 0d;

    public Double get_dir_x() {
       return dir_x;
    }
    public Double get_dir_y() {
        return dir_y;
    }
    public Double get_dir_z() {
        return dir_z;
    }
    public Double get_dir_w() {
        return dir_w;
    }

    public RotatView_add_new_point(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();

    }
    private void init() {
        vRecord = new VRecord();
        handler = new Handler() {

            @Override
            public void handleMessage(Message msg) {

                double detaTime = System.currentTimeMillis() - currentTime;
                switch (msg.what) {

                    case play: {
                        if (isClockWise) {
                            speed = speed - a * detaTime;
                            if (speed <= 0) {
                                return;
                            } else {
                                handler.sendEmptyMessageDelayed(play, delayedTime);
                            }
                        } else {
                            speed = speed + a * detaTime;
                            if (speed >= 0) {
                                return;
                            } else {
                                handler.sendEmptyMessageDelayed(play, delayedTime);
                            }
                        }

                        addDegree((float)(speed * detaTime + (a * detaTime * detaTime) / 2));
                        currentTime = System.currentTimeMillis();
                        invalidate();

                        break;
                    }
                    case stop: {
                        speed = 0;
                        handler.removeMessages(play);
                    }
                }

                super.handleMessage(msg);
            }
        };
        initSize();
    }

    public void setRotatBitmap(Bitmap bitmap) {
        rotatBitmap = bitmap;
        initSize();
        postInvalidate();
    }


    public void setRotatDrawableResource(int id) {
        BitmapDrawable drawable = (BitmapDrawable)getContext().getResources().getDrawable(id);
        setRotatDrawable(drawable);
    }

    public void setRotatDrawable(BitmapDrawable drawable) {
        rotatBitmap = drawable.getBitmap();
        initSize();
        postInvalidate();
    }

    public void setRotatDrawableResource_bitmap(Bitmap myBitmap) {
        setRotatDrawable_bitmap(myBitmap);
    }
    public void setRotatDrawable_bitmap(Bitmap myBitmap) {
        rotatBitmap = myBitmap;
        initSize();
        postInvalidate();
    }

    private void initSize() {
        if (rotatBitmap == null) {
            return;
        }
        width = rotatBitmap.getWidth();
        height = rotatBitmap.getHeight();

        maxwidth = Math.sqrt(width * width + height * height);
        
        o_x = o_y = (float)(maxwidth / 2);
    }
    private void addDegree(float added) {
        deta_degree += added;
        if (deta_degree > 360 || deta_degree < -360) {
            deta_degree = deta_degree % 360;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Matrix matrix = new Matrix();
        matrix.setTranslate((float)width / 2, (float)height / 2);
        matrix.preRotate(deta_degree);
        float my_angle=deta_degree;
        if(deta_degree<0)
            my_angle=360+deta_degree;

        float robot_angle=0;
        if(my_angle<270)
            robot_angle=-(my_angle-90);
        else
            robot_angle=-(my_angle-90)+360;
        Double myangle=(robot_angle/180)*PI;
        dir_x = Math.sin(0/2)*Math.cos(0/2)*Math.cos(myangle/2)-Math.cos(0/2)*Math.sin(0/2)*Math.sin(myangle/2);
        dir_y = Math.cos(0/2)*Math.sin(0/2)*Math.cos(myangle/2)+Math.sin(0/2)*Math.cos(0/2)*Math.sin(myangle/2);
        dir_z = Math.cos(0/2)*Math.cos(0/2)*Math.sin(myangle/2)-Math.sin(0/2)*Math.sin(0/2)*Math.cos(myangle/2);
        dir_w = Math.cos(0/2)*Math.cos(0/2)*Math.cos(myangle/2)+Math.sin(0/2)*Math.sin(0/2)*Math.sin(myangle/2);
        matrix.preTranslate(-(float)width / 2, -(float)height / 2);
        matrix.postTranslate((float)(maxwidth - width) / 2, (float)(maxwidth - height) / 2);
        canvas.drawBitmap(rotatBitmap, matrix,paint);
        super.onDraw(canvas);
    }

    Paint paint=new Paint();
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // TODO Auto-generated method stub
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension((int)maxwidth, (int)maxwidth);

    }
    float down_x;
    float down_y;
    float target_x;
    float target_y;
    float up_x;
    float up_y;
    float current_degree;
    float up_degree;
    float deta_degree;
    double lastMoveTime = 0;
    public static final float a_min = 0.001f;
    public static final float a_add = 0.001f;
    float a = a_min;
    public static final float a_max = a_min * 5;
    double speed = 0;
    VRecord vRecord;
    boolean isClockWise;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
            // TODO Auto-generated method stub
            if (rotatBitmap == null) {

                throw new NoBitMapError("Error,No bitmap in RotatView_add_new_point!");
            }
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    down_x = event.getX();
                    down_y = event.getY();
                    current_degree = detaDegree(o_x, o_y, down_x, down_y);
                    vRecord.reset();
                    a = a_max;
                    break;

                }
                case MotionEvent.ACTION_MOVE: {
                    down_x = target_x = event.getX();
                    down_y = target_y = event.getY();
                    float degree = detaDegree(o_x, o_y, target_x, target_y);
                    float dete = degree - current_degree;
                    if (dete < -270) {
                        dete = dete + 360;
                    } else if (dete > 270) {
                        dete = dete - 360;
                    }
                    lastMoveTime = System.currentTimeMillis();
                    vRecord.add(dete, lastMoveTime);
                    addDegree(dete);
                    current_degree = degree;
                    postInvalidate();

                    break;
                }
                case MotionEvent.ACTION_CANCEL:
                case MotionEvent.ACTION_UP: {
                    break;
                }
            }

        return true;
    }
    float detaDegree(float src_x, float src_y, float target_x, float target_y) {

        float detaX = target_x - src_x;
        float detaY = target_y - src_y;
        double d;
        if (detaX != 0) {
            float tan = Math.abs(detaY / detaX);

            if (detaX > 0) {

                if (detaY >= 0) {
                    d = Math.atan(tan);

                } else {
                    d = 2 * Math.PI - Math.atan(tan);
                }

            } else {
                if (detaY >= 0) {

                    d = Math.PI - Math.atan(tan);
                } else {
                    d = Math.PI + Math.atan(tan);
                }
            }

        } else {
            if (detaY > 0) {
                d = Math.PI / 2;
            } else {

                d = -Math.PI / 2;
            }
        }

        return (float)((d * 180) / Math.PI);
    }

    static class NoBitMapError extends RuntimeException {
        private static final long serialVersionUID = 1L;
        public NoBitMapError(String detailMessage) {
            super(detailMessage);
        }

    }
    static class VRecord {
        int addCount;
        public static final int length = 15;
        double[][] record = new double[length][2];
        public void add(double detadegree, double time) {

            for (int i = length - 1; i > 0; i--) {
                record[i][0] = record[i - 1][0];
                record[i][1] = record[i - 1][1];
            }
            record[0][0] = detadegree;
            record[0][1] = time;
            addCount++;

        }
        public static final double max_speed = 8;
        public double getSpeed() {

            if (addCount == 0) {
                return 0;
            }
            int maxIndex = Math.min(addCount, length) - 1;

            if ((record[0][1] - record[maxIndex][1]) == 0) {
                return 0;
            }

            double detaTime = record[0][1] - record[maxIndex][1];
            double sumdegree = 0;
            for (int i = 0; i < length - 1; i++) {
                sumdegree += record[i][0];
            }
            double result = sumdegree / detaTime;
            if (result > 0) {
                return Math.min(result, max_speed);
            } else {
                return Math.max(result, -max_speed);
            }
        }
        public void reset() {
            addCount = 0;
            for (int i = length - 1; i > 0; i--) {
                record[i][0] = 0;
                record[i][1] = 0;
            }
        }
    }
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if(rotatBitmap!=null){
        rotatBitmap.recycle();
        rotatBitmap=null;
        }
    }
}
